package data;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheManager;

import search.DealSearchEngine;

import models.DealModel;

import com.googlecode.objectify.Key;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.ObjectifyOpts;
import com.googlecode.objectify.ObjectifyService;
import com.googlecode.objectify.Query;

public class DealData {
	private static Objectify ofy;

	private static Cache cache = null;

	private static String prefix = "dealData_";

	private static boolean isRegisted = false;

	private static ObjectifyOpts opts = null;

	private int limit = 46;

	private int page = 1;

	private int totalPage = 1;

	private int totalResult = 0;

	private List<DealModel> listResult = new ArrayList<DealModel>();

	public static void init() {
		if (!isRegisted) {
			try {
				ObjectifyService.register(DealModel.class);
			} catch (Exception e) {

			}
			try {
				cache = CacheManager.getInstance().getCacheFactory()
						.createCache(Collections.emptyMap());
			} catch (CacheException e) {

			}
			opts = new ObjectifyOpts().setSessionCache(true);
			isRegisted = true;
		}
		ofy = ObjectifyService.begin(opts);
	}

	public List<DealModel> getListResult() {
		return listResult;
	}

	public int getLimit() {
		return limit;
	}

	public void setLimit(int limit) {
		this.limit = limit;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public int getTotalPage() {
		totalPage = totalResult / limit;
		if ((totalResult % limit) > 0) {
			totalPage += 1;
		}
		return totalPage;
	}

	public DealData() {
		init();
	}

	@SuppressWarnings("unchecked")
	public static void insert(DealModel deal) {
		init();
		if (cache != null) {
			cache.put(prefix + deal.getDealId(), deal);
		}
		ofy.put(deal);
		DealSearchEngine.update(deal);
	}

	public static DealModel getById(String id) {
		init();
		DealModel deal = new DealModel();
		if (cache != null && cache.containsKey(prefix + id)) {
			deal = (DealModel) cache.get(prefix + id);
		} else {
			try {
				deal = ofy.get(new Key<DealModel>(DealModel.class, id));
				if (deal.getStatus() != 2) {
					cache.remove(prefix + id);
					deal = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
				deal = null;
			}
		}
		return deal;
	}

	@SuppressWarnings("unchecked")
	public static DealModel getDemoById(String id) {
		init();
		DealModel deal = new DealModel();
		if (cache != null && cache.containsKey(prefix + "demo" + id)) {
			deal = (DealModel) cache.get(prefix + "demo" + id);
		} else {
			try {
				deal = ofy.get(new Key<DealModel>(DealModel.class, id));
				cache.put(prefix + "demo" + id, deal);
			} catch (Exception e) {
				deal = null;
			}
		}
		return deal;
	}

	public static DealModel getDealMarketing(String cityId, String categoryId) {
		init();
		DealModel deal = new DealModel();
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("endTime >", Calendar.getInstance().getTime())
				.filter("city", cityId).filter("dealType", 1)
				.filter("status", 2);
		if (cityId != null && !cityId.isEmpty()) {
			q = q.filter("city", cityId);
		}
		if (categoryId != null && !categoryId.isEmpty()
				&& !categoryId.equals("all")) {
			q = q.filter("category", categoryId);
		}
		List<DealModel> list = new ArrayList<DealModel>();
		for (DealModel dealModel : q) {
			list.add(dealModel);
		}
		Collections.sort(list);
		if (list.size() > 0)
			deal = list.get(0);
		return deal;
	}

	public void getTodayDeal(String cityId) {
		init();
		Calendar cal1 = Calendar.getInstance();
		Calendar cal2 = Calendar.getInstance();
		cal1.set(Calendar.HOUR_OF_DAY, 0);
		cal1.set(Calendar.MINUTE, 0);
		cal1.set(Calendar.SECOND, 0);
		cal1.set(Calendar.MILLISECOND, 0);
		cal2.set(Calendar.HOUR_OF_DAY, 23);
		cal2.set(Calendar.MINUTE, 59);
		cal2.set(Calendar.SECOND, 59);
		cal2.set(Calendar.MILLISECOND, 0);
		listResult = new ArrayList<DealModel>();
		int start = (page - 1) * limit;
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("doc >", cal1.getTime())
				.filter("doc <", cal2.getTime()).filter("city", cityId)
				.filter("dealType", 0).filter("status", 2);
		totalResult = q.count();
		q = q.limit(limit).offset(start);
		for (DealModel deal : q) {
			listResult.add(deal);
		}
	}

	public void getRecentDeal(String cityId) {
		init();
		listResult = new ArrayList<DealModel>();
		int start = (page - 1) * limit;
		Calendar cal = Calendar.getInstance();
		cal.set(Calendar.DATE, cal.get(Calendar.DATE) - 2);
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("doc >", cal.getTime()).filter("city", cityId)
				.filter("dealType", 0).filter("status", 2);
		totalResult = q.count();
		q = q.limit(limit).offset(start);
		for (DealModel deal : q) {
			if (deal.getEndTime().compareTo(Calendar.getInstance().getTime()) > 0) {
				listResult.add(deal);
			}
		}
	}

	public void getByCityAndCategory(String cityId, String categoryId) {
		init();
		listResult = new ArrayList<DealModel>();
		int start = (page - 1) * limit;
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("endTime >=", Calendar.getInstance().getTime())
				.filter("city", cityId).filter("category", categoryId)
				.filter("dealType", 0).filter("status", 2);
		totalResult = q.count();
		// q = q.limit(limit).offset(start);
		for (DealModel deal : q) {
			listResult.add(deal);
		}
		Collections.sort(listResult);
		if (listResult.size() >= (start + limit)) {
			listResult = listResult.subList(start, start + limit);
		} else {
			if (start > listResult.size()) {
				page = 1;
				listResult = listResult.subList(0, limit);
			} else {
				listResult = listResult.subList(start, listResult.size());
			}
		}
	}

	public void getByCity(String city) {
		init();
		listResult = new ArrayList<DealModel>();
		int start = (page - 1) * limit;
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("endTime >=", Calendar.getInstance().getTime())
				.filter("city", city).filter("status", 2);
		totalResult = q.count();
		// q = q.limit(limit).offset(start);
		DealModel marketing = DealData.getDealMarketing(city, null);
		if (marketing == null) {
			marketing = new DealModel();
		}
		for (DealModel deal : q) {
			if (!marketing.getDealId().equals(deal.getDealId())) {
				listResult.add(deal);
			}
		}
		Collections.sort(listResult);
		if (listResult.size() >= (start + limit)) {
			listResult = listResult.subList(start, start + limit);
		} else {
			if (start > listResult.size()) {
				page = 1;
				listResult = listResult.subList(0, limit);
			} else {
				listResult = listResult.subList(start, listResult.size());
			}
		}
	}

	public ArrayList<DealModel> getDealActive() {
		init();
		ArrayList<DealModel> deals = new ArrayList<DealModel>();
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("startTime <=", Calendar.getInstance().getTime())
				.filter("status", 1);

		for (DealModel deal : q) {
			deals.add(deal);
		}
		return deals;
	}

	public ArrayList<DealModel> getDealRunning() {
		init();
		ArrayList<DealModel> deals = new ArrayList<DealModel>();
		Query<DealModel> q = ofy.query(DealModel.class)
				.filter("endTime <=", Calendar.getInstance().getTime())
				.filter("status", 2);

		for (DealModel deal : q) {
			deals.add(deal);
		}
		return deals;
	}

	public ArrayList<DealModel> getByListId(List<String> ids) {
		init();
		ArrayList<DealModel> deals = new ArrayList<DealModel>();
		Map<String, DealModel> lst = ofy.get(DealModel.class, ids);
		for (int i = 0; i < ids.size(); i++) {
			deals.add(lst.get(ids.get(i)));
		}
		return deals;
	}
}
